﻿#include "FITKAcousticsDiscModel.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKMessage.h"
#include "FITK_Kernel/FITKCore/FITKVec3D.h"

#include "FITKAcousticsTriangles.h"
#include "FITKAcousticsDiscNodeList.h"
#include "FITKAcousticsFEModel.h"
#include "FITKAcousticsFENodeMap.h"
#include "FITKAcousticsSEAModel.h"
#include "FITKAbstractSEASubSys.h"
#include "FITKAbstractSEAFace.h"
#include "FITKAbstractJunction.h"

#include "FITK_Component/FITKAbaqusData/FITKAbaqusPart.h"
#include "FITK_Component/FITK2DMeshTools/FITKAbstractRecogClosedSpace.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMeshPartVTK.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTri.h"

#include <QSet>

namespace Acoustics
{
    FITKAcousticsDiscModel* FITKAcousticsDiscModel::_DsicModel = nullptr;

    FITKAcousticsDiscModel::FITKAcousticsDiscModel()
    {
        //创建对象
        _nodeList = new FITKAcousticsDiscNodeList;
        _seaModel = new FITKAcousticsSEAModel;
        _feModel = new FITKAcousticsFEModel;
        _junctionManager = new FITKJunctionManager;
    }

    FITKAcousticsDiscModel::~FITKAcousticsDiscModel()
    {
        //释放对象
        if (_nodeList) delete _nodeList;
        if (_seaModel) delete _seaModel;
        if (_feModel) delete _feModel;
        if (_junctionManager) delete _junctionManager;
    }

    FITKAcousticsDiscModel* FITKAcousticsDiscModel::GetDiscModelFromFrame()
    {
        if (FITKAPP == nullptr) return nullptr;
        //从全局对象获取
        return FITKAPP->getGlobalData()->getMeshData<FITKAcousticsDiscModel>();
    }

    FITKAcousticsDiscNodeList* FITKAcousticsDiscModel::getNodes()
    {
        return _nodeList;
    }

    FITKAcousticsSEAModel* FITKAcousticsDiscModel::getSEAModel()
    {
        return _seaModel;
    }

    FITKAcousticsFEModel* FITKAcousticsDiscModel::getFEModel()
    {
        return _feModel;
    }

    FITKJunctionManager* FITKAcousticsDiscModel::getJunctionManager()
    {
        return _junctionManager;
    }

    QList<int> FITKAcousticsDiscModel::getUnUsedNodeIDs()
    {
        QList<int> nodeIDList;
        if (_nodeList == nullptr) return nodeIDList;
        //获取全部节点id
        _nodeList->getAllNodeID(nodeIDList);
        //去除SEA模型中的节点id
        if (_seaModel && _seaModel->getSEASubSysManager())
        {
            FITKAcousticsSEASubSysManager* subsysMgr = _seaModel->getSEASubSysManager();
            const int n = subsysMgr->getDataCount();
            for (int i = 0; i < n; ++i)
            {
                FITKAbstractSEASubSys* sys = subsysMgr->getDataByIndex(i);
                if (sys == nullptr) continue;
                //当前子系统节点ID列表
                QList<int> nodeIDs = sys->getTriangleNodeIDs();

                for (int id : nodeIDs)
                    nodeIDList.removeAll(id);
                //节点列表已经清空，全部节点被使用，退出循环
                if (nodeIDList.isEmpty()) break;
            }
        }
        //去除FE模型中的节点id
        if (_feModel)
        {

        }
        return nodeIDList;
    }

    QList<int> FITKAcousticsDiscModel::getUsedNodeIDs()
    {
        if (_nodeList == nullptr) return QList<int>();
        QList<int> allNodes;
        //获取全部节点id
        _nodeList->getAllNodeID(allNodes);
        //获取未使用的id
        QList<int> unUsedIDList = this->getUnUsedNodeIDs();
        
        QSet<int> allNodeSet = allNodes.toSet();
        QSet<int> unUseNodeSet = unUsedIDList.toSet();
        QSet<int> differenceSet = allNodeSet.subtract(unUseNodeSet);
        QList<int> resultList = differenceSet.toList();

        return resultList;
    }

    QList<QPair<int, int>> FITKAcousticsDiscModel::getFreeEdge()
    {
        AppFrame::FITKMessageNormal("Start Check Free Edge ...");
        QList<QPair<int, int>> nodeIDsBoundary;
        nodeIDsBoundary.append(this->getSEASubSysFreeEdge());
        nodeIDsBoundary.append(this->getFESubSysFreeEdge());
        AppFrame::FITKMessageNormal(QString("Check Finish ! Free Edge Number : %1").arg(nodeIDsBoundary.size()));
        return nodeIDsBoundary;
    }

    void FITKAcousticsDiscModel::updataFENodesMap()
    {
        if (!_feModel || !_seaModel) return;
        //获取FE节点映射器
        FITKAcousticsFENodeMapManager* nodeFEMapMgr = _feModel->getNodesMapManager();
        if (!nodeFEMapMgr) return;

        //获取part管理器
        AbaqusData::FITKAbaqusPartManager* partMgr = _feModel->getPartManager();
        if (!partMgr) return;

        int count = partMgr->getDataCount();
        for (int i = 0; i < count; ++i)
        {
            //获取部件
            AbaqusData::FITKAbaqusPart* partData = partMgr->getDataByIndex(i);
            if (!partData) continue;
            int partID = partData->getDataObjectID();
            //不在创建新映射
            if (nodeFEMapMgr->getFENodeMapByPartID(partID)) continue;
            //获取部件的网格信息
            Interface::FITKAbaMeshPartVTK* mesh = partData->getMesh();
            if (!mesh) continue;
            int nodeNum = mesh->getNodeCount();
            if (nodeNum <= 0)continue;
            //开始映射节点数据
            FITKAcousticsFENodeMap* nodesMap = new FITKAcousticsFENodeMap;
            nodeFEMapMgr->appendDataObj(nodesMap);
            nodesMap->setPartID(partID);
            for (int j = 0; j < nodeNum; ++j)
            {
                Core::FITKNode* node = mesh->getNodeAt(j);
                if (!node)continue;
                int nodeID = node->getNodeID();
                Acoustics::DiscNode* nodeDisc = _nodeList->addDiscNode(node->x(), node->y(), node->z());
                if (!nodeDisc)return;
                int nodeDiscID = nodeDisc->getNodeID();
                nodeDisc->setNodeSource(Acoustics::DiscNodeSourceType::DiscNodeSource::FEM);
                nodeDisc->setSourceID(partID);
                nodeDisc->setSourceNodeID(nodeID);
                nodesMap->setNodeMap(nodeID, nodeDiscID);
            }
        }
    }

    void FITKAcousticsDiscModel::clearDiscModel()
    {
        if (_nodeList) _nodeList->removeAllNode();
        if (_feModel) _feModel->clearFEModel();
        if (_seaModel)_seaModel->clearSEAModel();
        if (_junctionManager) _junctionManager->clear();
    }

    QList<QPair<int, int>> FITKAcousticsDiscModel::getSEASubSysFreeEdge()
    {
        QList<QPair<int, int>> nodeIDsBoundary;
        if (!_nodeList || !_seaModel) return nodeIDsBoundary;
        //获取面管理器
        FITKSEAFaceManager* faceManager = _seaModel->getSEAFaceManager();
        if (!faceManager) return nodeIDsBoundary;
        //存储点和单元
        QList<Core::FITKNode*> nodeList;
        QList<Interface::FITKElementTri3*> eleList;
        QHash<int, int> eleIndexShellIDMap;
        int count = _nodeList->getNodeCount();
        //获取节点数据
        for (int i = 0; i < count; ++i)
        {
            Core::FITKNode* nodeData = _nodeList->getNodeAt(i);
            if (!nodeData)continue;
            nodeList.append(nodeData);
        }
        //获取单元数据
        count = faceManager->getDataCount();
        for (int i = 0; i < count; ++i)
        {
            Acoustics::FITKAbstractSEAFace* faceData = faceManager->getDataByIndex(i);
            if (!faceData)continue;
            //获取第一个关联的板对象
            Acoustics::FITKAbstractSEASubSys* shellData = faceData->getAConnectedShellSubSys();
            if (shellData == nullptr)continue;
            //获取网格数据
            Acoustics::FITKAcousticsTriangles* mesh = faceData->getTriangleMesh();
            if (!mesh)continue;
            int shellID = shellData->getDataObjectID();
            //获取单元
            int eleNum = mesh->getElementCount();
            for (int i = 0; i < eleNum; ++i)
            {
                Interface::FITKElementTri3* ele = dynamic_cast<Interface::FITKElementTri3*>(mesh->getElementAt(i));
                if (!ele) continue;
                int elemIndex = eleList.size();
                eleList.append(ele);
                eleIndexShellIDMap.insert(elemIndex, shellID);
            }
        }
        if (nodeList.isEmpty() || eleList.isEmpty()) return nodeIDsBoundary;
        //计算封闭空间
        Interface::FITKAbstractRecogClosedSpace * space = Interface::FITKAbstractRecogClosedSpace::createFITKRecogClosedSpace();
        if (!space->initMesh(nodeList, eleList)) return nodeIDsBoundary;
        QList<QPair<int, int>> bound = space->getBoundary();
        delete space;
        //获取自由边
        for (QList<QPair<int, int>>::iterator iter = bound.begin(); iter < bound.end(); ++iter)
        {
            int nodeIndex1 = iter->first, nodeIndex2 = iter->second;
            if (nodeList.size() <= nodeIndex1 || nodeList.size() <= nodeIndex2)continue;
            Core::FITKNode *node1 = nodeList.at(nodeIndex1), *node2 = nodeList.at(nodeIndex2);
            if (!node1 || !node2)continue;
            int node1ID = node1->getNodeID();
            int node2ID = node2->getNodeID();
            nodeIDsBoundary.append(QPair<int, int>(node1ID, node2ID));
            AppFrame::FITKMessageNormal(QString("SEA Free Edge Node pairs : %1, %2").arg(node1ID).arg(node2ID));
        }
        return nodeIDsBoundary;
    }

    QList<QPair<int, int>> FITKAcousticsDiscModel::getFESubSysFreeEdge()
    {
        QList<QPair<int, int>> nodeIDsBoundary;
        return nodeIDsBoundary;
    }
}


